
#include <BMesh>
#include "member_BCone.h"

using namespace BWE;

member_BCone::member_BCone(BCone* cone)
{
	boss = cone;
	radius = 0;
	height = 0;
	sides = 12;
	segments = 1;
	bottomSegments = 1;
	prepare();
}
member_BCone::~member_BCone()
{

}

void member_BCone::prepare()
{
	if (sines.size() != sides)
	{
		sines.resize(sides);
		coses.resize(sides);
		for (int i = 0; i < sides; i++)
		{
			float angle = (float)(i * PI / sides * 2);
			coses[i] = cos(angle);
			sines[i] = sin(angle);
		}
	}
}
void member_BCone::rebuild()
{
	if (segments < 1)
		return;

	int flankNumVerts = sides * segments + 1;
	int bottomNumVerts = sides * bottomSegments + 1;
	int totalNumVerts = flankNumVerts + bottomNumVerts;

	BVectorArray* vertices = boss->vertices();
	BVectorArray* normals = boss->normals();

	if (!vertices || vertices->size() != totalNumVerts)
	{
		vertices = new BVectorArray(totalNumVerts);
		normals = new BVectorArray(totalNumVerts);
		boss->setVertices(vertices);
		boss->setNormals(normals);
	}

	boss->clearElements();

	{// make flank vertices.
		float sth = 1.0f / sides;
		float stv = 1.0f / segments;
		float sr = radius / segments;
		float sh = height / segments;
		for (int j = 0; j < segments; j++)
		{
			float r = radius - sr * j;
			float z = sh * j;
			int head = j * sides;
			for (int i = 0; i < sides; i++)
			{
				float x = (float)coses[i] * r;
				float y = (float)sines[i] * r;
				vertices->set(head + i, BVector(x, y, z));
				BVector normal(x, y, z);
				normal.normalize();
				normals->set(head + i, normal);
			}
		}
		(*vertices)[flankNumVerts - 1] = BVector(0, 0, height);
		(*normals)[flankNumVerts - 1] = BVector(0, 0, 1);
	}

	{//make flank quads and central triangles.
		BIndexArray* flankIndices = new BIndexArray(sides * (segments - 1) * 4);
		BElement* flankPrimitive = new BElement(Primitive_Quads, flankIndices);
		for (int r = 0; r < segments - 1; r++)
		{
			int head = sides * r;
			int pos = sides * r * 4;
			for (int c = 0; c < sides; c++)
			{
				int index0 = head + c;
				int index1 = head + (c + 1) % sides;
				int index2 = index0 + sides;
				int index3 = index1 + sides;
				(*flankIndices)[pos + c * 4] = index0;
				(*flankIndices)[pos + c * 4 + 1] = index1;
				(*flankIndices)[pos + c * 4 + 2] = index3;
				(*flankIndices)[pos + c * 4 + 3] = index2;
			}
		}
		boss->addElement(flankPrimitive);

		// make top triangles
		BIndexArray* topIndices = new BIndexArray(sides * 3);
		BElement* topPrimitive = new BElement(Primitive_Triangles, topIndices);
		int head = flankNumVerts - 1 - sides;
		int top = flankNumVerts - 1;
		for (int i = 0; i < sides; i++)
		{
			int index0 = head + i;
			int index1 = head + (i + 1) % sides;
			(*topIndices)[i * 3] = index0;
			(*topIndices)[i * 3 + 1] = index1;
			(*topIndices)[i * 3 + 2] = top;
		}
		boss->addElement(topPrimitive);
	}

	{// make bottom vertices.
		BVector bottomNormal(0, 0, -1);
		float dr = radius / bottomSegments;
		for (int j = 0; j < bottomSegments; j++)
		{
			float r = radius - dr * j;
			int head = flankNumVerts + j * sides;
			for (int i = 0; i < sides; i++)
			{
				float x = coses[i] * r;
				float y = sines[i] * r;
				vertices->set(head + i, BVector(x, y, 0));
				normals->set(head + i, bottomNormal);
			}
		}
		(*vertices)[totalNumVerts - 1] = BVector(0, 0, 0);
		(*normals)[totalNumVerts - 1] = bottomNormal;
	}

	if (bottomNumVerts < 1)
	{
		BIndexArray* bottomIndices = new BIndexArray(sides);
		BElement* bottomPrimitive = new BElement(Primitive_Polygon, bottomIndices);
		int first = flankNumVerts;
		for (int i = 0; i < sides; i++)
		{
			(*bottomIndices)[i] = first + i;
		}
		boss->addElement(bottomPrimitive);
	}
	else
	{
		BIndexArray* bottomIndices = new BIndexArray(sides * (bottomSegments - 1) * 4);
		BElement* bottomPrimitive = new BElement(Primitive_Quads, bottomIndices);

		for (int r = 0; r < bottomSegments - 1; r++)
		{
			int head = flankNumVerts + sides * r;
			int pos = r * sides * 4;
			for (int c = 0; c < sides; c++)
			{
				int index0 = head + c;
				int index1 = head + (c + 1) % sides;
				int index2 = index0 + sides;
				int index3 = index1 + sides;
				(*bottomIndices)[pos + c * 4] = index0;
				(*bottomIndices)[pos + c * 4 + 1] = index2;
				(*bottomIndices)[pos + c * 4 + 2] = index3;
				(*bottomIndices)[pos + c * 4 + 3] = index1;
			}
		}
		boss->addElement(bottomPrimitive);

		BIndexArray* bottomCentralIndices = new BIndexArray(sides * 3);
		BElement* bottomCentralPrimitive = new BElement(Primitive_Triangles, bottomCentralIndices);
		int head = totalNumVerts - sides - 1;
		int center = totalNumVerts - 1;
		for (int i = 0; i < sides; i++)
		{
			int index0 = head + i;
			int index1 = head + (i + 1) % sides;
			(*bottomCentralIndices)[i * 3] = index0;
			(*bottomCentralIndices)[i * 3 + 1] = center;
			(*bottomCentralIndices)[i * 3 + 2] = index1;
		}
		boss->addElement(bottomCentralPrimitive);
	}
}
